package logic

import (
	"context"

	"laundry-service/app/client/internal/repo"
	"laundry-service/app/client/internal/svc"
	"laundry-service/app/client/internal/types"
	"laundry-service/entity"

	"github.com/zeromicro/go-zero/core/logx"
)

type ProductlistLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewProductlistLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ProductlistLogic {
	return &ProductlistLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ProductlistLogic) Productlist(req *types.ProductlistReq) (resp *types.ProductlistReply, err error) {
	// 第一步：查询商品ID列表（不查询完整商品信息）
	productIds, cn, err := l.getProductIds(req)
	if err != nil {
		return nil, err
	}

	if len(productIds) == 0 {
		return &types.ProductlistReply{Cn: cn, Data: []*types.ProductListItem{}}, nil
	}

	// 第二步：从缓存批量获取商品信息
	cachedProducts, missedIds, err := l.svcCtx.ProductCache.GetProducts(productIds)
	if err != nil {
		logx.Errorf("批量获取商品缓存失败: %v", err)
		// 缓存失败时降级到数据库查询
		return l.fallbackToDatabase(req)
	}

	// 第三步：查询缓存未命中的商品
	var missedProducts []*entity.Product
	if len(missedIds) > 0 {
		missedProducts, err = l.svcCtx.Db.GetProductsByIds(missedIds)
		if err != nil {
			logx.Errorf("查询未命中商品失败: %v", err)
			return nil, err
		}

		// 将查询到的商品写入缓存
		for _, product := range missedProducts {
			if err := l.svcCtx.ProductCache.SetProduct(product); err != nil {
				logx.Errorf("设置商品缓存失败: %v", err)
			}
		}
	}

	// 第四步：合并结果并按原始顺序排序
	allProducts := l.mergeProducts(productIds, cachedProducts, missedProducts)

	// 第五步：转换为响应格式
	result := make([]*types.ProductListItem, 0, len(allProducts))
	for _, product := range allProducts {
		if product != nil {
			res := &types.ProductListItem{
				ID:            product.ID,
				CategoryId:    product.CategoryId,
				Name:          product.Name,
				Url:           product.Url,
				Price:         product.Price,
				BagCategoryId: product.BagCategoryId,
				Remark:        product.Remark,
			}
			result = append(result, res)
		}
	}

	return &types.ProductlistReply{Cn: cn, Data: result}, nil
}

// 查询商品ID列表（只查询ID，不查询完整信息）
func (l *ProductlistLogic) getProductIds(req *types.ProductlistReq) ([]int, int64, error) {
	// 直接使用UserDao的ListProduct方法获取商品列表，然后提取ID
	products, count, err := l.svcCtx.Db.(*repo.UserDao).ListProduct(req)
	if err != nil {
		return nil, 0, err
	}

	// 提取商品ID
	var productIds []int
	for _, product := range products {
		productIds = append(productIds, int(product.ID))
	}

	return productIds, count, nil
}

// 合并缓存和数据库查询结果，保持原始顺序
func (l *ProductlistLogic) mergeProducts(productIds []int, cached map[int]*entity.Product, missed []*entity.Product) []*entity.Product {
	// 将missed转换为map
	missedMap := make(map[int]*entity.Product)
	for _, product := range missed {
		missedMap[product.ID] = product
	}

	// 按原始顺序合并
	result := make([]*entity.Product, len(productIds))
	for i, id := range productIds {
		if product, exists := cached[id]; exists {
			result[i] = product
		} else if product, exists := missedMap[id]; exists {
			result[i] = product
		}
	}

	return result
}

// 降级到数据库查询
func (l *ProductlistLogic) fallbackToDatabase(req *types.ProductlistReq) (*types.ProductlistReply, error) {
	data, cn, err := l.svcCtx.Db.ListProduct(req)
	if err != nil {
		return nil, err
	}

	result := make([]*types.ProductListItem, 0)
	for _, v := range data {
		res := &types.ProductListItem{
			ID:            v.ID,
			CategoryId:    v.CategoryId,
			Name:          v.Name,
			Url:           v.Url,
			Price:         v.Price,
			BagCategoryId: v.BagCategoryId,
			Remark:        v.Remark,
		}
		result = append(result, res)
	}

	return &types.ProductlistReply{Cn: cn, Data: result}, nil
}
